package com.dudu.interceptor;

import com.alibaba.fastjson.JSON;
import com.dudu.cache.Cache;
import com.dudu.exception.BusinessException;
import com.dudu.exception.ErrorCode;
import com.dudu.exception.PermissionDeniedException;
import com.dudu.model.vo.AppRequest;
import com.dudu.util.Const;
import com.dudu.util.ResponseBuilder;
import com.dudu.util.WebResponse;
import com.dudu.util.WebResponseHelper;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by dudu on 2016/12/24.
 */
@Slf4j
@Aspect
@Component
public class AuthTokenInterceptor {

    private static Set<String> WHITE_SET = new HashSet<>();

    @Resource
    private Cache cache;

    static {
        WHITE_SET.add("token");
    }

    @Around("@within(org.springframework.stereotype.Controller)")
    public Object intercept(ProceedingJoinPoint p) throws Throwable {
        log.debug("start controller {}", p.getSignature());

        Object res = null;
        if (p.getArgs() != null && p.getArgs().length == 1) {
            Object arg = p.getArgs()[0];
            if (arg instanceof AppRequest) {
                AppRequest<?> request = (AppRequest<?>) arg;
                long start = System.currentTimeMillis();
                log.info("start | {} | {}", p.getSignature(), JSON.toJSON(request));

                try {
                    if (check(request, p)) {
                        try {
                            res = p.proceed();
                        } catch (BusinessException e) {
                            log.error("{}, catch  BusinessException:{} {}", p.getSignature(), e, e.getErrorCode());
                            res = WebResponseHelper.error(e.getErrorCode());
                        } catch (IllegalArgumentException e) {
                            log.error("{}, catch  IllegalArgumentException:{} {}", p.getSignature(), e, e.getMessage());
                            res = WebResponseHelper.error(ErrorCode.PARAMS_ERROR);
                        }  catch (PermissionDeniedException e) {
                            log.error("{}, catch  PermissionDeniedException:{} {}", p.getSignature(), e, e.getMessage());
                            res = WebResponseHelper.error(ErrorCode.PERMISSION_DENIED_ERROR);
                        }catch (Exception e) {
                            log.error("{}, catch  Exception:{} {}", p.getSignature(), e, e.getMessage());
                            res = WebResponseHelper.error(ErrorCode.SYSTEM_ERROR);
                        }finally {

                        }
                    } else {
                        res = ResponseBuilder.create(ErrorCode.PERMISSION_DENIED_ERROR).build();
                    }
                } catch (Exception e) {

                } finally {
                    long end = System.currentTimeMillis();
                    if (res instanceof WebResponse) {
                        log.info("end | {} | {} | {} | {}", p.getSignature(), ((WebResponse<?>) res).getCode(),
                            ((WebResponse<?>) res).getMsg(), (end - start));
                    } else {
                        log.info("end | proxy | {}", (end - start));
                    }
                }
            } else {
                res = p.proceed();
            }
        } else {
            res = p.proceed();
        }

        log.info("end controller {}", p.getSignature());

        return res;
    }

    private boolean check(AppRequest<?> request, ProceedingJoinPoint p) {
        if (WHITE_SET.contains(p.getSignature().getName())) {
            return true;
        }

        if (StringUtils.hasText(request.getToken()) == false) {
            log.error("AuthTokenInterceptor: token is needed!");
            return false;
        }

        String uuid = request.getUuid();
        if(cache.exists(Const.TOKEN_PREFIX + uuid)) {
            String token = (String) cache.getValue(Const.TOKEN_PREFIX + uuid);
            if(!request.getToken().equalsIgnoreCase(token)) {// 校验token
                log.error("AuthTokenInterceptor: token is invalid!");
                return false;
            }
        } else {
            log.error("AuthTokenInterceptor: uuid is invalid!");
            return false;
        }
        Long ts = request.getTs();
        if(ts > System.currentTimeMillis() || System.currentTimeMillis()
            - ts > 10 * 60 * 1000) {
            log.error("AuthTokenInterceptor: ts is invalid!");
            return false;
        }


        return true;
    }
}
